package au.edu.unsw.editingtool.authentication;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;

import edu.vt.middleware.ldap.Authenticator;
import edu.vt.middleware.ldap.Ldap;
import edu.vt.middleware.ldap.LdapConfig;

import au.edu.unsw.editingtool.global.EditingToolException;
import au.edu.unsw.editingtool.global.EditingToolPropertyReader;
import au.edu.unsw.editingtool.global.EditingToolUtil;

import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchResult;

public class LDAP {
	
    private Hashtable<String, String> attributes;
    private boolean authenticated;

    public Hashtable<String, String> getAttributes() {
        return this.attributes;
    }

    public void setAttributes(Hashtable<String, String> attributes) {
        this.attributes = attributes;
    }

    public boolean isValid() {
        return this.authenticated;
    }

    public void setValid(boolean result) {
        this.authenticated = result;
    }
    
	private String propertyFile = "";
	
	public void setPropertyFile(String file) {
		this.propertyFile = file;
	}
	
    public boolean authenticate(String username, String password) {
               
        EditingToolPropertyReader reader = new EditingToolPropertyReader();
        LdapConfig ldapConfig = new LdapConfig();
        
        reader.setFile(this.propertyFile);
        reader.setFilter(EditingToolPropertyReader.LDAP);
        try {
			reader.retrieveProperties();
		} catch (IOException e) {
			EditingToolException ex = new EditingToolException();
			ex.setMessage("Getting Error When Process Property File.");
			e.printStackTrace();
		}
        
        Hashtable<String, String> properties = reader.getProperties();
        
        ldapConfig.setHost(properties.get("host"));
        ldapConfig.setPort(properties.get("port"));
        ldapConfig.setBase(properties.get("userBase"));
        
        Authenticator authenticator = new Authenticator(ldapConfig);
        if (properties.get("authorizationFilter").trim().length() != 0)
        	authenticator.setAuthorizationFilter(properties.get("authorizationFilter"));
        
        authenticator.setSubtreeSearch(properties.get("subtreeSearch").equals("true"));
        authenticator.setUserField(properties.get("userField"));
        authenticator.setUser(username);
        authenticator.setCredential(password);
        
        try {
        	authenticator.useTls(false);
        	
        	this.authenticated = authenticator.authenticate(username, password);
        	
        	
        	if ((this.authenticated) && (properties.get("attributes").length() != 0)) {
        		Hashtable<String, String> attributes = (Hashtable<String, String>) EditingToolUtil.splitString(properties.get("attributes"), ",", new Hashtable<String, String>());
        		this.attributes = retrieveAttributes(ldapConfig, properties.get("userField"), username, attributes);
        	}
        	
        } catch (Exception e) {
        	EditingToolException ex = new EditingToolException();
        	ex.setMessage("Getting Error When Using LDAP Authentication.");
        	e.printStackTrace();
        }
        
        return this.authenticated;
    }
    
    private Hashtable<String, String> retrieveAttributes(LdapConfig ldapConfig, 
    													 String userField,
    													 String user, 
    													 Hashtable<String, String> keys) throws Exception {
    	Hashtable<String, String> result = new Hashtable<String, String>();
    	
    	Ldap ldap = new Ldap(ldapConfig);
    	
    	Iterator results = ldap.search(userField + "=" + user);
    	while (results.hasNext()) {
    		SearchResult searchresult = (SearchResult) results.next();
    		NamingEnumeration allAttributes = searchresult.getAttributes().getAll();
    		
    		while(allAttributes.hasMore()) {
    			Attribute current = (Attribute) allAttributes.next();
    			if (keys.containsKey(current.getID())) {
    				NamingEnumeration values = current.getAll();
    				while (values.hasMore()) {
    					result.put(current.getID(), values.next().toString());
    				}
    			}
    		}
    	}

    	return result;
    }
    
}